package ecscore

import (
	"log"
	"reflect"
)

type componentMap = map[reflect.Type]interface{}

// / EntitySimpleStorage stores entities within
// / a id-keyed map
// / EntitySimpleStorage is comatibale with EntityStorage
// / they have same interfaces
type EntitySimpleStorage struct {
	eid EntityId
	// data is a map of {EntityId: cpnTypes}
	data map[EntityId]componentMap
}

func NewEntitySimpleStorage() *EntitySimpleStorage {
	return &EntitySimpleStorage{
		data: map[EntityId]componentMap{},
	}
}

// / add component to Entity with entityid
func (e *EntitySimpleStorage) AddEnt(eid EntityId, cpns ...interface{}) {
	if _, existsData := e.data[eid]; existsData {
		log.Panicf("duplicate entity was added to EntitySimpleStorage: %v", eid)
	}

	e.data[eid] = make(componentMap)

	for _, cpn := range cpns {
		e.data[eid][reflect.TypeOf(cpn)] = cpn
	}
}

func (e *EntitySimpleStorage) DeleteEnt(eid EntityId) {
	delete(e.data, eid)
}

// / Find all Entity Id by provided ComponentTypes
func (e *EntitySimpleStorage) FindAll(cpnTypes []reflect.Type) []EntityId {
	result := []EntityId{}

	for eid, cpns := range e.data {
		matches := true

		for _, cpnType := range cpnTypes {
			if _, existsTy := cpns[cpnType]; !existsTy {
				matches = false
				continue
			}
		}

		if !matches {
			continue
		}

		result = append(result, eid)
	}

	return result
}

func (e *EntitySimpleStorage) GetComponent(eid EntityId, cpnType reflect.Type) interface{} {
	return e.data[eid][cpnType]
}

func (e *EntitySimpleStorage) Get(eid EntityId) []interface{} {
	cpns := e.data[eid]
	result := make([]interface{}, len(cpns))
	idx := 0

	for _, cpn := range cpns {
		result[idx] = cpn
		idx++
	}

	return result
}

func (e *EntitySimpleStorage) GetComponentMap(eid EntityId) componentMap {
	return e.data[eid]
}

func (e *EntitySimpleStorage) RemoveComponent(eid EntityId, cpnType reflect.Type) {
	delete(e.data[eid], cpnType)
}

func (e *EntitySimpleStorage) AddComponent(eid EntityId, cpn interface{}) {
	e.data[eid][reflect.TypeOf(cpn)] = cpn
}
